package com.example.springframeworklearning.validator;

import com.example.springframeworklearning.domain.Order;
import com.example.springframeworklearning.domain.OrderItem;
import com.example.springframeworklearning.validator.annotation.ValidateOrder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 范型需要关联：用哪一个注解校验哪一个对象
 *
 * @author luo
 * @since 2022/9/21 15:22
 */
@Slf4j
@Component
public class OrderConstraintValidator implements /*ConstraintValidator<ValidateOrder, Order>,*/ Validator {

    /**
     * 在校验器中，即使没有被放入到ioc中，也是可以进行依赖注入的
     */
    private static  OrderItemValidator orderItemValidator;

    /**
     * 每次校验都会创建 OrderConstraintValidator 对象
     * 所以 OrderConstraintValidator 不能存储状态，
     * 如果非要存储的话，就使用 static 关键字
     */
    private final static AtomicInteger ORDER_ID_GENERATOR = new AtomicInteger(0);

    public OrderConstraintValidator(OrderItemValidator orderItemValidator) {
        if (OrderConstraintValidator.orderItemValidator == null) {
            OrderConstraintValidator.orderItemValidator = orderItemValidator;
        }

        log.info("每次校验都会创建：{}", orderItemValidator);
    }


   /* @Override
    public boolean isValid(Order value, ConstraintValidatorContext context) {
        return isValid(value);
    }*/

    private boolean isValid(Order value) {
        if (value.getId() == null) {
//            id 不存在，校验失败
            return false;
        }
        if (value.getId() < ORDER_ID_GENERATOR.get()) {
//            id 已存在，校验失败
            return false;
        }
        ORDER_ID_GENERATOR.incrementAndGet();
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return Order.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {

        Order order = (Order) target;
        log.info("校验：{}", order);
        if (!isValid(order)) {
//            ValidationUtils.rejectIfEmpty(errors,"name","错误code","订单名称不能为空");
            errors.rejectValue("id", "无效的订单id");


            if (CollectionUtils.isEmpty(order.getOrderItemList())) {

                errors.rejectValue("orderItemList", "订单项不能为空");
                return;
            }



            /**
             * 校验嵌套的 list 对象
             * https://stackoverflow.com/questions/12680730/validate-a-list-of-nested-objects-with-spring-validator
             */
            for (int i = 0; i < order.getOrderItemList().size(); i++) {
                errors.pushNestedPath("orderItemList["+i+"]");
                ValidationUtils.invokeValidator(orderItemValidator, order.getOrderItemList().get(i), errors);
                errors.popNestedPath();
            }


        }
    }
}
